home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Libraries / MCC Utils / MCFileInfo.p < prev    next >
Encoding:
Text File  |  1994-05-04  |  26.3 KB  |  882 lines  |  [TEXT/PJMM]

  1. {This document is formated in monaco 9 pt                                          }
  2. {                                                                                  }
  3. {LEGAL STUFF                                                                       }
  4. {                                                                                  }
  5. {Copyright © 1994 by University of Melbourne. All Rights Reserved. This work is    }
  6. {provided "as is" and without any express or implied warranties, including,        }
  7. {without limitation, the implied warranties of merchantability and fitness         }
  8. {for a particular purpose.                                                         }
  9. {                                                                                  }
  10. {University of Melbourne is not responsible for the consequences of the use of this}
  11. {work, regardless of the cause. You may use this work in a public domain,          }
  12. {freeware, or shareware product with no restrictions, as long as you include       }
  13. {the following notice in your product's about box or splash screen:                }
  14. {  "Portions Copyright © 1994 by University of Melbourne".                         }
  15. {If you use more than 50 lines of this work, please credit the author also:        }
  16. {  "Portions by Michael Cutter"                                                    }
  17. {Public domain is defined as something that you release to the public, without     }
  18. {copyright and without restrictions on use. Freeware is a copyrighted work,        }
  19. {for which you charge no money. Shareware is a copyrighted work for which you      }
  20. {charge a fee if the user decides to keep it. If you intend to use this work       }
  21. {in a commercial product, please contact us.                                       }
  22. {                                                                                  }
  23. {                                                                                  }
  24. {OTHER STUFF                                                                       }
  25. {                                                                                  }
  26. {AUTHOR:                                                                           }
  27. { Michael Trevor Cutter                                                            }
  28. {                                                                                  }
  29. {CONTACT:                                                                          }
  30. {  Internet:                                                                       }
  31. {    mtc@arbld.unimelb.edu.au (Preferred)                                          }
  32. {  Snail Mail:                                                                     }
  33. {    Dept of Architecture & Building                                               }
  34. {    University of Melbourne                                                       }
  35. {    Parkville VIC 3052                                                            }
  36. {    AUSTRALIA                                                                     }
  37. {                                                                                  }
  38. {PERSONAL STUFF                                                                    }
  39. {  I'd really appreciate it if you'd let me know what you're using my code         }
  40. {  in, (send me email or a postcard). Please report any bugs or errors to me.      }
  41. {                                                                                  }
  42. {MODULE DESCRIPTION                                                                }
  43. {This unit provides functions for obtaining various information about files and    }
  44. {folders. The functions were created on an 'as needed' basis, so there isn't much  }
  45. {rhyme or reason to them. They are just my best go at doing what I needed to do.   }
  46. {Please feel free to make suggestions about how they might be improved, I always   }
  47. {enjoy constructive criticism :-)                                                  }
  48.  
  49. unit MCFileInfo;
  50. interface
  51.     uses
  52.         Folders,{}
  53.         MCCompatibility, MCCursor, MCHandlesAndStrs;
  54.     function GestaltAvailable: boolean;
  55.     function GestHasFSSpecCalls: boolean;
  56.  
  57. {returns true if the FSSpec _file_ exists}
  58.     function MCFSSpecExists (myFSSpec: FSSpec): boolean;
  59.  
  60. {get a directory string path from a dirid and vrefnum}
  61.     function MCPathNameFromDirID (DirID: longint;
  62.                                     vRefnum: integer): string;
  63.  
  64. {get the type and creator of a file}
  65.     function MCGetTypeCrtr (myfs: FSSpec;
  66.                                     var ftype, crtr: OSType): OSErr;
  67.     function MCGetType (myfs: FSSpec;
  68.                                     var ftype: OSType): OSErr;
  69.     function MCGetCrtr (myfs: FSSpec;
  70.                                     var crtr: OSType): OSErr;
  71.  
  72. {get and set the namelocked bit of a file}
  73.     function MCLockName (myfs: FSSpec): OSErr;
  74.     function MCUnlockName (myfs: FSSpec): OSErr;
  75.     function MCGetNameLock (myfs: FSSpec;
  76.                                     var namelock: Boolean): OSErr;
  77.  
  78. {list the contents of a directory in a displayable form - not very good}
  79. {and a bit buggy}
  80.     function MCListDirectory (vrefnum: integer;
  81.                                     dirid: Longint;
  82.                                     longlist: boolean;
  83.                                     listall: boolean;
  84.                                     markdirs: boolean): Handle;
  85.  
  86. {much more efficient method of searching a directory}
  87. {Gives a return delimited list of all the files/folders in the given}
  88. {directory. Easily modified to do a recursive search of all subfolders}
  89.     function MCSearchCatalog (MinimumItems: integer;
  90.                                     vrefnumtosearch: integer;
  91.                                     DirIDToSearch: Longint;
  92.                                     findfolders: boolean;
  93.                                     findfiles: boolean;
  94.                                     ignorenoaccessfolders: boolean): Handle;
  95.  
  96. {returns the vrefnum and dirid of the current Blessed system folder}
  97.     function MCFindSystemFolder (var foundVRefNum: integer;
  98.                                     var foundDirID: longint): OSErr;
  99.  
  100. {gets the vrefnum of the named volume}
  101.     function MCGetVrefNum (volname: str255;
  102.                                     var vrefnum: integer): OSErr;
  103.  
  104. {returns true if the error given is because a file is busy}
  105.     function MCIsBusyError (err: OSErr): boolean;
  106.  
  107. {returns true if the given FSSpec points to a folder}
  108.     function MCFSSpecIsFolder (myfs: FSSpec): boolean;
  109.  
  110. {returns true if the given FSSpec file is busy}
  111.     function MCFSSpecIsBusy (myfs: FSSpec): boolean;
  112.  
  113. {gets the name of a volume given its vrefnum}
  114.     function MCGetVolName (vrefnum: integer;
  115.                                     var volname: str255): OSErr;
  116.  
  117. {gets the last item in a string path, i.e.the file name }
  118.     function MCGetLeafOfPath (path: str255): str255;
  119.  
  120. {returns true if a user can _READ_ the files in a dir (remember to check myAccess before }
  121. {trying to write to it)}
  122. { FOR SOME STUPID REASON< I HAVE TO PASS IN A COMPLETE PATH TO GET THIS TO WORK!!!!}
  123. {ANYONE KNOW WHAT I'M DOING WRONG?}
  124. {myAccess comes back as 'wrs' if total r/w able, and '-' in place of any that are not there}
  125. {e.g. '-rs' - Similar to Unix permissions}
  126.     function MCUserCanAccessDir (volname: Str255;
  127.                                     vrefnum: integer;
  128.                                     dirID: longint;
  129.                                     var myAccess: str255;
  130.                                     var myErr: OSErr): boolean;
  131.  
  132. {returns the directory id of the directory specified in myFS}
  133.     function MCGetDirIDofDir (myFS: FSSpec;
  134.                                     isvolume: Boolean;
  135.                                     var dirid: longint): OSErr;
  136. implementation
  137.  
  138. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  139. {•• returns true if _Gestalt trap is available. Remember that it may not work, }
  140. {tho - it may not recognise attributes ••}
  141.     function GestaltAvailable: boolean;
  142.         const
  143.             _Gestalt = $A1AD;
  144.     begin
  145.         GestaltAvailable := TrapAvailable(_Gestalt);
  146.     end;
  147.  
  148. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  149. {•• returns true if the current system supports FSSpec calls ••}
  150.     function GestHasFSSpecCalls: boolean;
  151. {This function is called by all the below functions that use FSSpec calls, to }
  152. {see whether they are available. If FSSpec calls are not, the function either }
  153. {aborts if necessary, or uses the System 6 compatible methods.}
  154.         var
  155.             myFeature: longint;
  156.             myErr: OSErr;
  157.             myBit: integer;
  158.     begin
  159.         if GestaltAvailable then
  160.             myErr := Gestalt(gestaltFSAttr, myFeature)
  161.         else
  162.             GestHasFSSpecCalls := false;
  163.         if myerr <> noErr then
  164.             GestHasFSSpecCalls := false
  165.         else
  166.             begin
  167.                 myBit := gestaltHasFSSpecCalls;
  168.                 if BitTst(@myFeature, 31 - myBit) then
  169.                     GestHasFSSpecCalls := true
  170.                 else
  171.                     GestHasFSSpecCalls := false;
  172.             end;
  173.     end;
  174.  
  175. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  176. {•• returns true if the file but not folder exists. Should expand to cope with folders. ••}
  177.     function MCFSSpecExists (myFSSpec: FSSpec): boolean;
  178.         var
  179.             myErr: OSErr;
  180.             tmpstr: str255;
  181.             fsrefnum: integer;
  182.     begin
  183. {system 7 compatible, fails if system 6 - probably a bit naughty trying to open the file, but its a quick and sure way...}
  184.         if GestHasFSSpecCalls then
  185.             begin
  186.                 myerr := FSpOpenDF(myFSSpec, fsRdPerm, fsrefnum);
  187.                 if (myerr = -43) or (myerr = -35) or (myerr = -120) then
  188.                     MCFSSpecExists := false
  189.                 else
  190.                     begin
  191.                         myerr := FSClose(fsrefnum);
  192.                         MCFSSpecExists := true; {even if myerr <> noErr, must still exist}
  193.                     end;
  194.             end
  195.         else
  196.             MCFSSpecExists := false; {not system 7 - what else can I do?}
  197.     end;
  198.  
  199. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  200. {•• finds a pathname from a dirid and vrefnum ••}
  201. {system 6 & 7 compatible}
  202.     function MCPathNameFromDirID;
  203.         var
  204.             Block: CInfoPBRec;
  205.             directoryName, FullPathName: str255;
  206.             err: oserr;
  207.  
  208.     begin
  209.         FullPathName := '';
  210.         with block do
  211.             begin
  212.                 ioNamePtr := @directoryName;
  213.                 ioDrParID := DirId;
  214.             end;
  215.  
  216.         repeat
  217.  
  218.             with block do
  219.                 begin
  220.                     ioVRefNum := vRefNum;
  221.                     ioFDirIndex := -1;
  222.                     ioDrDirID := block.ioDrParID;
  223.                 end;
  224.             err := PBGetCatInfo(@Block, FALSE);
  225.             if err <> noerr then
  226.                 begin
  227.                     MCPathNameFromDirID := 'An error has occured.';
  228.                     exit(MCPathNameFromDirID);
  229.                 end;
  230.             directoryName := concat(directoryName, ':');
  231.             fullPathName := concat(directoryName, fullPathName);
  232.         until block.ioDrDirID = 2;
  233.  
  234.         MCPathNameFromDirID := fullPathName;
  235.     end;
  236.  
  237. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  238.     function MCGetTypeCrtr (myfs: FSSpec;
  239.                                     var ftype, crtr: OSType): OSErr;
  240.         var
  241.             myFinfo: FInfo;
  242.             myErr: OSErr;
  243.     begin
  244.         myErr := FSpGetFInfo(myfs, myFinfo);
  245.         MCGetTypeCrtr := myErr;
  246.         if myErr = noErr then
  247.             begin
  248.                 crtr := myFInfo.fdCreator;
  249.                 ftype := myFInfo.fdType;
  250.             end;
  251.     end;
  252.  
  253.     function MCGetType (myfs: FSSpec;
  254.                                     var ftype: OSType): OSErr;
  255.         var
  256.             myFinfo: FInfo;
  257.             myErr: OSErr;
  258.     begin
  259.         myErr := FSpGetFInfo(myfs, myFinfo);
  260.         MCGetType := myErr;
  261.         if myErr = noErr then
  262.             ftype := myFInfo.fdType;
  263.     end;
  264.  
  265.     function MCGetCrtr (myfs: FSSpec;
  266.                                     var crtr: OSType): OSErr;
  267.         var
  268.             myFinfo: FInfo;
  269.             myErr: OSErr;
  270.     begin
  271.         myErr := FSpGetFInfo(myfs, myFinfo);
  272.         MCGetCrtr := myErr;
  273.         if myErr = noErr then
  274.             crtr := myFInfo.fdCreator;
  275.     end;
  276.  
  277.  
  278. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  279. {•• name lock functions ••}
  280.     const
  281.         kNameLockedBit = 12;
  282.     function MCLockName (myfs: FSSpec): OSErr;
  283.         var
  284.             myfinfo: FInfo;
  285.             flg: longint;
  286.         procedure COSErr (err: OSErr);
  287.         begin
  288.             if err <> noErr then
  289.                 begin
  290.                     MCLockName := err;
  291.                     exit(MCLockName);
  292.                 end;
  293.         end;
  294.     begin
  295.         MCLockName := noErr;
  296.         COSErr(FSpGetFInfo(myfs, myfinfo));
  297.         flg := myfinfo.fdFlags;
  298.         BSet(flg, kNameLockedBit);
  299.         myfinfo.fdFlags := flg;
  300.         COSErr(FSpSetFInfo(myfs, myfinfo));
  301.     end;
  302.  
  303.     function MCUnlockName (myfs: FSSpec): OSErr;
  304.         var
  305.             myfinfo: FInfo;
  306.             flg: longint;
  307.         procedure COSErr (err: OSErr);
  308.         begin
  309.             if err <> noErr then
  310.                 begin
  311.                     MCUnlockName := err;
  312.                     exit(MCUnlockName);
  313.                 end;
  314.         end;
  315.     begin
  316.         MCUnlockName := noErr;
  317.         COSErr(FSpGetFInfo(myfs, myfinfo));
  318.         flg := myfinfo.fdFlags;
  319.         BClr(flg, kNameLockedBit);
  320.         myfinfo.fdFlags := flg;
  321.         COSErr(FSpSetFInfo(myfs, myfinfo));
  322.     end;
  323.  
  324.     function MCGetNameLock (myfs: FSSpec;
  325.                                     var namelock: Boolean): OSErr;
  326.         var
  327.             myfinfo: FInfo;
  328.         procedure COSErr (err: OSErr);
  329.         begin
  330.             if err <> noErr then
  331.                 begin
  332.                     MCGetNameLock := err;
  333.                     exit(MCGetNameLock);
  334.                 end;
  335.         end;
  336.     begin
  337.         MCGetNameLock := noErr;
  338.         COSErr(FSpGetFInfo(myfs, myfinfo));
  339.         namelock := BTst(myfinfo.fdFlags, kNameLockedBit);
  340.     end;
  341.  
  342. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  343. {•• Directory listing function ••}
  344.     function MCListDirectory (vrefnum: integer;
  345.                                     dirid: Longint;
  346.                                     longlist: boolean;
  347.                                     listall: boolean;
  348.                                     markdirs: boolean): Handle;
  349.         var
  350.             FName: Str255;
  351.             myCPB: CInfoPBRec;
  352.             err: OSErr;
  353.             TotalFiles, TotalDirectories: integer;
  354.             htext: Handle;
  355.             retpos: integer;
  356.             returnstr, colonstr: str255;
  357.  
  358.         procedure EnumerateCatalog (dirIDToSearch: longint);
  359.             var
  360.                 index, i, tmpint: integer;
  361.                 indent: str255;
  362.         begin {EnumerateCatalog}
  363.             index := 1;
  364.             repeat
  365.                 MCNextAnimCursor;
  366. {set up the search}
  367.                 FName := '';
  368.                 myCPB.ioFDirIndex := index;
  369.                 myCPB.ioDrDirID := dirIDToSearch;
  370.  
  371.                 err := PBGetCatInfo(@myCPB, FALSE); {actually get the information}
  372.  
  373.                 if err = noErr then
  374.                     if BitTst(@myCPB.ioFlAttrib, 3) then
  375.  
  376.                         begin {we have a directory}
  377.                             TotalDirectories := TotalDirectories + 1;
  378.                             hlock(htext);
  379.                             if not listall and (bitand(myCPB.ioDrUsrWds.frFlags, fInvisible) <> 0) then
  380. {if it is invisible and not list all}
  381.                                 begin {don't list it}
  382.                                 end
  383.                             else
  384.                                 begin {list a folder}
  385.                                     if myCPB.ioNamePtr^ <> '' then
  386.                                         begin
  387. {strip any tailing returns, like the one after Icon...}
  388.                                             retpos := pos(returnstr, myCPB.ioNamePtr^);
  389.                                             if retpos > 0 then
  390.                                                 delete(myCPB.ioNamePtr^, retpos, 1);
  391.                                             err := MCAppendStrToHndl(myCPB.ioNamePtr^, htext);
  392. {if listall, then list them all, bimbo}
  393.                                             if markdirs then
  394.                                                 err := MCAppendStrToHndl(colonstr, htext);
  395.                                             if longlist then
  396.                                                 begin
  397.                                                     indent := '';
  398.                                                     tmpint := 35 - length(myCPB.ioNamePtr^);
  399.                                                     for i := 1 to tmpint do
  400.                                                         indent := concat(indent, ' ');
  401.                                                     err := MCAppendStrToHndl(concat(indent, 'Folder'), htext);
  402.                                                 end;
  403.  
  404.                                             err := MCAppendReturnToHndl(htext);
  405.                                         end;
  406.                                 end;
  407.                             hunlock(htext);
  408.                             err := 0;  {clear error return on way back}
  409.                         end {if BitTst}
  410.                     else
  411.  
  412.                         begin {we have a file}
  413.                             TotalFiles := TotalFiles + 1;
  414.                             hlock(htext);
  415.                             if not listall and (bitand(myCPB.ioFLFndrInfo.fdFlags, fInvisible) <> 0) then {if it is invisible and not list all}
  416.                                 begin {don't list it}
  417.                                 end
  418.                             else
  419.                                 begin {list a file}
  420.                                     if myCPB.ioNamePtr^ <> '' then
  421.                                         begin
  422. {strip any tailing returns, like the one after Icon...}
  423.                                             retpos := pos(returnstr, myCPB.ioNamePtr^);
  424.                                             if retpos > 0 then
  425.                                                 delete(myCPB.ioNamePtr^, retpos, 1);
  426.                                             err := MCAppendStrToHndl(myCPB.ioNamePtr^, htext);
  427.  
  428.                                             if longlist then
  429.                                                 begin
  430.                                                     indent := '';
  431.                                                     tmpint := 35 - length(myCPB.ioNamePtr^);
  432.                                                     for i := 1 to tmpint do
  433.                                                         indent := concat(indent, ' ');
  434.                                                     err := MCAppendStrToHndl(concat(indent, myCPB.ioflFndrInfo.fdType, '  ', myCPB.ioflFndrInfo.fdCreator), htext);
  435.                                                 end;
  436.  
  437.                                             err := MCAppendReturnToHndl(htext);
  438.                                         end;
  439.                                 end;
  440.                             hunlock(htext);
  441.     {EnumerateCatalog(myCPB.ioDrDirID); {only call this if we want a recursive search}
  442.                             err := 0;  {clear error return on way back}
  443.                         end; {else}
  444.                 index := index + 1;
  445.             until (err <> noErr);
  446.         end;  {EnumerateCatalog}
  447.  
  448.  
  449.     begin    {EnumerShell}
  450.         TotalFiles := 0;
  451.         TotalDirectories := 0;
  452.  
  453.         FName := '';
  454.  
  455.         with MyCPB do
  456.             begin
  457.                 ioNamePtr := @FName;
  458.                 ioVrefNum := vrefnum;
  459.             end; {with}
  460.  
  461. {allocate storate for the list}
  462.         htext := NewHandle(0);
  463.         returnstr := chr(13);  {----•••• do you need this? Yes, you bimbo!!}
  464.         colonstr := ':';
  465.  
  466. {search the specified directory}
  467.         EnumerateCatalog(dirid);
  468.  
  469. {return the information}
  470.         MCListDirectory := htext;
  471.     end;    {MCSearchCatalog}
  472.  
  473. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  474. {•• Directory searching function ••}
  475.  
  476. {This procedure searches a specified directory, and returns either a list of folders, }
  477. {files or both.}
  478. {if folders are wanted, you can also specify a minimum number of items to be in the folder}
  479.  
  480.     function MCSearchCatalog (MinimumItems: integer;
  481.                                     vrefnumtosearch: integer;
  482.                                     DirIDToSearch: Longint;
  483.                                     findfolders: boolean;
  484.                                     findfiles: boolean;
  485.                                     ignorenoaccessfolders: boolean): Handle;
  486.         var
  487.             FName: Str255;
  488.             myCPB: CInfoPBRec;
  489.             err: OSErr;
  490.             TotalFiles, TotalDirectories: integer;
  491.             htext: Handle;
  492.             strlen: integer;
  493.             returnstr: str255;
  494.  
  495.         procedure EnumerateCatalog (minitems: integer;
  496.                                         dirIDToSearch: longint);
  497. {performs the same function as PBCatSearch - From TN #68, I think...}
  498.             var
  499.                 index: integer;
  500.                 access: str255;{ignore}
  501.  
  502.         begin {EnumerateCatalog}
  503.             index := 1;
  504.             repeat
  505.                 MCNextAnimCursor;
  506. {set up the search}
  507.                 FName := '';
  508.                 myCPB.ioFDirIndex := index;
  509.                 myCPB.ioDrDirID := dirIDToSearch;
  510.  
  511.                 err := PBGetCatInfo(@myCPB, FALSE); {actually get the information}
  512.  
  513.                 if err = noErr then
  514.                     if BitTst(@myCPB.ioFlAttrib, 3) then
  515.                         begin {we have a directory}
  516.                             TotalDirectories := TotalDirectories + 1;
  517.                             if findfolders then
  518.                                 if myCPB.ioDrNmFls >= minitems then
  519.                                     if ignorenoaccessfolders then
  520.                                     {make sure we aren't collecting folders which the user can't access}
  521.                                         begin
  522.                                             if MCUserCanAccessDir(FName, myCPB.ioVrefnum, myCPB.ioDirID, access, err) then
  523.                                                 begin
  524.                                                     strlen := length(myCPB.ioNamePtr^);
  525.                                                     hlock(htext);
  526.                                                 {append the string}
  527.                                                     err := ptrAndHand(ptr(ord4(@myCPB.ioNamePtr^) + 1), htext, strlen);
  528.                                             {append a return after the string}
  529.                                                     err := ptrAndHand(ptr(ord4(@returnstr) + 1), htext, 1);
  530.                                                     hunlock(htext)
  531.                                                 end;
  532.                                         end
  533.                                     else {if list every folder}
  534.                                         begin {output the name of the folder in some manner}
  535.                                             strlen := length(myCPB.ioNamePtr^);
  536.                                             hlock(htext);
  537.                                         {append the string}
  538.                                             err := ptrAndHand(ptr(ord4(@myCPB.ioNamePtr^) + 1), htext, strlen);
  539.                                         {append a return after the string}
  540.                                             err := ptrAndHand(ptr(ord4(@returnstr) + 1), htext, 1);
  541.                                             hunlock(htext)
  542. {writeln(myCPB.ioNamePtr^) {if greater than minitems}
  543.                                         end
  544.                                 else
  545. {do nothing if has 0 items}
  546.                                     ;
  547. {EnumerateCatalog(myCPB.ioDrDirID); {only call this if we want a recursive search}
  548.                             err := 0;  {clear error return on way back}
  549.                         end {if BitTst}
  550.                     else
  551.                         begin {we have a file}
  552.                             TotalFiles := TotalFiles + 1;
  553.                             if findfiles then
  554.                                 begin
  555.                                     strlen := length(myCPB.ioNamePtr^);
  556.                                     hlock(htext);
  557.                                     err := ptrAndHand(ptr(ord4(@myCPB.ioNamePtr^) + 1), htext, strlen);
  558.                                     err := ptrAndHand(ptr(ord4(@returnstr) + 1), htext, 1);
  559.                                     hunlock(htext)
  560.                                 end;
  561.                         end; {else}
  562.                 index := index + 1;
  563.             until (err <> noErr);
  564.         end;  {EnumerateCatalog}
  565.  
  566.  
  567.     begin    {EnumerShell}
  568.         TotalFiles := 0;
  569.         TotalDirectories := 0;
  570.  
  571.         with MyCPB do
  572.             begin
  573.                 ioNamePtr := @FName;
  574.                 ioVrefNum := vrefnumtosearch;
  575.             end; {with}
  576.  
  577. {allocate storate for the list}
  578.         htext := NewHandle(0);
  579.         returnstr := chr(13);
  580.  
  581. {search the specified directory}
  582.         EnumerateCatalog(MinimumItems, DirIDToSearch);
  583.  
  584. {return the information}
  585.         MCSearchCatalog := htext;
  586.     end;    {MCSearchCatalog}
  587.  
  588.  
  589. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  590. {•• finds the system folder in system 6 or 7. Untested. ••}
  591.     function MCFindSystemFolder (var foundVRefNum: integer;
  592.                                     var foundDirID: longint): OSErr;
  593. {Taken from code found in Q&A Stack}
  594.         var
  595.             gesResponse: longint;
  596.             envRec: SysEnvRec;
  597.             myWDPB: WDPBRec;
  598.             volName: str32;
  599.             err: OSerr;
  600.  
  601.     begin
  602.         MCFindSystemFolder := noErr;
  603.  
  604.         foundVRefNum := 0;
  605.  
  606.         foundDirID := 0;
  607.         if GestaltAvailable then
  608.             begin
  609.                 if (Gestalt(gestaltFindFolderAttr, gesResponse) = noErr) and (BitTst(@gesResponse, 31 - gestaltFindFolderPresent) = TRUE) then
  610.                     MCFindSystemFolder := FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, foundVRefNum, foundDirID);
  611.             end
  612.         else if (SysEnvirons(curSysEnvVers, envRec) = noErr) then
  613.             begin
  614.                 myWDPB.ioVRefNum := envRec.sysVRefNum;
  615.                 volName := '';                    {/* Zero volume name */}
  616.                 myWDPB.ioNamePtr := @volName;
  617.                 myWDPB.ioWDIndex := 0;
  618.                 myWDPB.ioWDProcID := 0;
  619.                 err := PBGetWDInfo(@myWDPB, false);
  620.                 if (err = noErr) then
  621.                     begin
  622.                         foundVRefNum := myWDPB.ioWDVRefNum;
  623.                         foundDirID := myWDPB.ioWDDirID;
  624.                     end
  625.                 else
  626.                     MCFindSystemFolder := err;
  627.             end;
  628.     end;
  629.  
  630. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  631. {•• returns a vrefnum for a specified volume name ••}
  632.     function MCGetVrefNum;
  633.         var
  634.             myFSSpec: FSSpec;
  635.             myErr: OSErr;
  636.             tmpvol: str255;
  637.             pbc: HParmBlkPtr;
  638.     begin
  639. {System 6 & 7 compatible}
  640.         if volname[length(volname)] <> ':' then
  641.             tmpvol := concat(volname, ':')
  642.         else
  643.             tmpvol := volname;
  644.         pbc := HParmBlkPtr(NewPtr(sizeof(HParamBlockRec)));
  645.         with pbc^ do
  646.             begin
  647.                 ioCompletion := nil;
  648.                 ioNamePtr := @tmpvol;
  649.                 ioVRefNum := 0;
  650.                 ioFDirIndex := 0;
  651.                 ioVolIndex := -1;
  652.             end;
  653.         myErr := PBHGetVInfo(pbc, FALSE);
  654.         if myErr = noErr then
  655.             begin
  656.                 vrefnum := pbc^.ioVrefNum;
  657.             end;
  658.         MCGetVrefNum := myErr;
  659.     end;
  660.  
  661. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  662. {•• returns true if error was caused because file was busy. ••}
  663.     function MCIsBusyError (err: OSErr): boolean;
  664.     begin
  665.         case err of
  666.             fBsyErr, opWrErr, afpFileBusy: 
  667.                 MCIsBusyError := true;
  668.             otherwise
  669.                 MCIsBusyError := false;
  670.         end;
  671.     end;
  672.  
  673. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  674. {•• returns true if file is open elsewhere ••}
  675.  
  676.     function MCFSSpecIsBusy (myfs: FSSpec): boolean; {must only be a file}
  677. {DOESN"T REALLY WORK...bit may be wrong...}
  678. {Don't really need it anyway, checkout MCGetFSSpecFileNoClose}
  679.         var
  680.             myCPB: CInfoPBRec;
  681.             err: OSErr;
  682.     begin
  683.         MCFSSpecIsBusy := false;
  684.         with MyCPB do
  685.             begin
  686.                 ioNamePtr := @myfs.name;
  687.                 ioVrefNum := myfs.vrefnum;
  688.                 ioDirID := myfs.parid;
  689.                 ioFDirIndex := 0;
  690.                 ioFlParID := myfs.parid;
  691.             end; {with}
  692.  
  693. {must test bit 7, whatever that translates to... I think it is 7-x, so here we use 0}
  694.         err := PBGetCatInfo(@myCPB, FALSE); {actually get the information}
  695.         if err = noErr then
  696.             if BitTst(@myCPB.ioFlAttrib, 1) then
  697.                 MCFSSpecIsBusy := true
  698.             else
  699.                 MCFSSpecIsBusy := false;
  700.     end;
  701.  
  702. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  703. {•• returns true if fsspec designates a folder ••}
  704.  
  705.     function MCFSSpecIsFolder (myfs: FSSpec): boolean;
  706.         var
  707.             myCPB: CInfoPBRec;
  708.             err: OSErr;
  709.     begin
  710.         MCFSSpecIsFolder := false;
  711.         with MyCPB do
  712.             begin
  713.                 ioNamePtr := @myfs.name;
  714.                 ioVrefNum := myfs.vrefnum;
  715.                 ioDirID := 0;
  716.                 ioDrDirID := 0;
  717.                 ioFDirIndex := 0;
  718.                 ioDrParID := myfs.parid;
  719.                 ioFlParID := myfs.parid;
  720.             end; {with}
  721.  
  722.         err := PBGetCatInfo(@myCPB, FALSE); {actually get the information}
  723.         if err = noErr then
  724.             if BitTst(@myCPB.ioFlAttrib, 3) then
  725.                 MCFSSpecIsFolder := true
  726.             else
  727.                 MCFSSpecIsFolder := false;
  728.     end;
  729.  
  730. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  731. {•• returns name of volume designated with vrefnum ••}
  732.  
  733.     function MCGetVolName (vrefnum: integer;
  734.                                     var volname: str255): OSErr;
  735.         var
  736.             pb: ParamBlockRec;
  737.     begin
  738.         volname := '';
  739.         with pb do
  740.             begin
  741.                 ioCompletion := nil;
  742.                 ioNamePtr := @volname;
  743.                 ioVrefNum := vrefnum;
  744.                 iovolIndex := 0;
  745.             end;
  746.         MCGetVolName := PBGetVInfo(@pb, false);
  747.     end;
  748.  
  749. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  750. {•• returns file/folder at end of path - if path ends with a ":", returns that ••}
  751.     function MCGetLeafOfPath (path: str255): str255;
  752.         var
  753.             offset: integer;
  754.             isfolder: boolean;
  755.     begin
  756.         if path[length(path)] = ':' then
  757.             begin
  758.                 path[length(path)] := '@';
  759.                 isfolder := true;
  760.             end
  761.         else
  762.             isfolder := false;
  763.         offset := pos(':', path);
  764.         repeat
  765.             delete(path, 1, offset);
  766.             offset := pos(':', path);
  767.         until offset = 0;
  768.         if isfolder then
  769.             if path[length(path)] = '@' then
  770.                 path[length(path)] := ':'; {convert back to folder}
  771.         MCGetLeafOfPath := path;
  772.     end;
  773.  
  774. {•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  775. {•• returns access privileges for a folder in the form: uu••}
  776.     function MCUserCanAccessDir (volname: Str255;
  777.                                     vrefnum: integer;
  778.                                     dirID: longint;
  779.                                     var myAccess: str255;
  780.                                     var myErr: OSErr): boolean;
  781.  
  782.         var
  783.             pb: HParamBlockRec;
  784.             accessprivs: longint;
  785.     begin
  786.         if (dirid <> 0) then {in case passed in a full path name}
  787.             volname := MCPathNameFromDirID(dirid, vrefnum);
  788.         with pb do
  789.             begin
  790.                 ioCompletion := nil;
  791.                 ioNamePtr := @volname;
  792.                 ioVrefNum := vrefnum;
  793.                 ioDirID := dirid;
  794.             end;
  795.         myErr := PBHGetDirAccess(@pb, false);
  796. {at the moment, we only care if the user has access to it or not.}
  797.         if myErr = noErr then
  798.             begin
  799.                 accessprivs := pb.ioACAccess;
  800.                 if accessprivs < 0 then
  801.                     accessprivs := (accessprivs - ($80000000)) div 16777216
  802.                 else
  803.                     accessprivs := accessprivs div 16777216;{get the high two bytes}
  804.                 case accessprivs of
  805.                     0: 
  806.                         begin
  807.                             MCUserCanAccessDir := false;
  808.                             myAccess := '---';
  809.                         end;
  810.                     1: 
  811.                         begin
  812.                             myAccess := '--s';
  813.                             MCUserCanAccessDir := false;
  814.                         end;
  815.                     2: 
  816.                         begin
  817.                             myAccess := '-r-';
  818.                             MCUserCanAccessDir := false;
  819.                         end;
  820.                     3: 
  821.                         begin
  822.                             myAccess := '-rs'; {minimum required to be able to read files in a dir, I think}
  823.                             MCUserCanAccessDir := true;
  824.                         end;
  825.                     4, 5, 6: 
  826.                         begin
  827.                             myAccess := '-rs';
  828.                             MCUserCanAccessDir := true;
  829.                         end;
  830.                     7: 
  831.                         begin
  832.                             myAccess := 'wrs';
  833.                             MCUserCanAccessDir := true;
  834.                         end;
  835.                     otherwise
  836.                         begin
  837.                             MCUserCanAccessDir := false;
  838.                             myAccess := '---';
  839.                         end;
  840.                 end;
  841.             end
  842.         else
  843.             begin
  844.                 MCUserCanAccessDir := false;
  845.             end;
  846.     end;
  847.  
  848.  
  849.     function MCGetDirIDofDir (myFS: FSSpec;
  850.                                     isvolume: Boolean;
  851.                                     var dirid: longint): OSErr;
  852.         var
  853.             myCPB: CInfoPBRec;
  854.             err: OSErr;
  855.             tmps: Str255;
  856.     begin
  857.         MCGetDirIDofDir := noErr;
  858.         if isvolume then
  859.             tmps := concat(myfs.name, ':')
  860.         else
  861.             tmps := myfs.name;
  862.         with MyCPB do
  863.             begin
  864.                 ioNamePtr := @tmps;
  865.                 ioVrefNum := myfs.vrefnum;
  866.                 ioDirID := 0;
  867.                 if isvolume then
  868.                     ioDrDirID := 0
  869.                 else
  870.                     ioDrDirID := myfs.parid;
  871.                 ioFDirIndex := 0;
  872.                 ioDrParID := myfs.parid;
  873.             end; {with}
  874.  
  875.         err := PBGetCatInfo(@myCPB, FALSE);
  876.         if err = noErr then
  877.             dirid := mycpb.ioDirID
  878.         else
  879.             MCGetDirIDofDir := err;
  880.     end;
  881.  
  882. end.